package com.my.chapter19;

import net.mindview.util.Enums;

import java.util.EnumMap;


public class Test {
    public static void main(String[] args) {
        RoShamBo5.main(args);
    }
}

enum Outcome{ WIN,LOSE,DRAW }

interface Competitor<T extends Competitor<T>>{
    Outcome compete(T competitor);
}

class RoShamBo{
    public static <T extends Competitor<T>>
    void match(T a,T b){
        System.out.println(a + " vs " + b + " ：" + a.compete(b));
    }

    public static <T extends Enum<T> & Competitor<T>>
    void play(Class<T> rsbClass,int size){
        for(int i=0;i<size;i++){
            match(Enums.random(rsbClass),Enums.random(rsbClass));
        }
    }
}

enum RoShamBo2 implements Competitor<RoShamBo2>{
    PAPER(Outcome.DRAW,Outcome.LOSE,Outcome.WIN),
    SCISSORS(Outcome.WIN,Outcome.DRAW,Outcome.LOSE),
    ROCK(Outcome.LOSE,Outcome.WIN,Outcome.DRAW);

    private Outcome vPAPER,vSCISSORS,vROCK;
    RoShamBo2(Outcome paper,Outcome scissors,Outcome rock){
        this.vPAPER = paper;
        this.vSCISSORS = scissors;
        this.vROCK = rock;
    }

    @Override
    public Outcome compete(RoShamBo2 it) {
        switch (it){
            default:
            case PAPER: return vPAPER;
            case SCISSORS: return vSCISSORS;
            case ROCK: return vROCK;
        }
    }

    public static void main(String[] args) {
        RoShamBo.play(RoShamBo2.class,6);
    }
}

enum RoShamBo3 implements Competitor<RoShamBo3>{
    ROCK{
        @Override
        public Outcome compete(RoShamBo3 opponent) {
            return compete(SCISSORS,opponent);
        }
    },
    SCISSORS{
        @Override
        public Outcome compete(RoShamBo3 opponent) {
            return compete(PAPER,opponent);
        }
    },
    PAPER{
        @Override
        public Outcome compete(RoShamBo3 opponent) {
            return compete(ROCK,opponent);
        }
    };

    Outcome compete(RoShamBo3 loser,RoShamBo3 oppoent){
        return ((oppoent == this) ? Outcome.DRAW :
                ((oppoent == loser) ? Outcome.WIN : Outcome.LOSE));
    }

    public static void main(String[] args) {
        RoShamBo.play(RoShamBo3.class,6);
    }
}

enum RoShamBo4 implements Competitor<RoShamBo4>{
    PAPER,SCISSORS,ROCK;
    static EnumMap<RoShamBo4,EnumMap<RoShamBo4,Outcome>>
                table = new EnumMap<RoShamBo4, EnumMap<RoShamBo4, Outcome>>(RoShamBo4.class);
    static {
        for(RoShamBo4 it : RoShamBo4.values()){
            table.put(it,new EnumMap<RoShamBo4, Outcome>(RoShamBo4.class));
        }
        initRow(PAPER,Outcome.DRAW,Outcome.LOSE,Outcome.WIN);
        initRow(SCISSORS,Outcome.WIN,Outcome.DRAW,Outcome.LOSE);
        initRow(ROCK,Outcome.LOSE,Outcome.WIN,Outcome.DRAW);
    }
    static void initRow(RoShamBo4 it,Outcome vPAPER,Outcome vSCISSORS,Outcome vROCK){
        EnumMap<RoShamBo4,Outcome> row = RoShamBo4.table.get(it);
        row.put(RoShamBo4.PAPER,vPAPER);
        row.put(RoShamBo4.SCISSORS,vSCISSORS);
        row.put(RoShamBo4.ROCK,vROCK);
    }
    public Outcome compete(RoShamBo4 it){
        return table.get(this).get(it);
    }

    public static void main(String[] args) {
        RoShamBo.play(RoShamBo4.class,6);
    }
}

enum RoShamBo5 implements Competitor<RoShamBo5>{
    PAPER,SCISSORS,ROCK;
    private static Outcome[][] table = {
            {Outcome.DRAW,Outcome.LOSE,Outcome.WIN},//PAPER
            {Outcome.WIN,Outcome.DRAW,Outcome.LOSE},//SCISSORS
            {Outcome.LOSE,Outcome.WIN,Outcome.DRAW},//ROCK
    };
    public Outcome compete(RoShamBo5 other){
        return table[this.ordinal()][other.ordinal()];
    }

    public static void main(String[] args) {
        RoShamBo.play(RoShamBo5.class,6);
    }
}

/*Output：
ROCK vs ROCK ：DRAW
SCISSORS vs ROCK ：LOSE
SCISSORS vs ROCK ：LOSE
SCISSORS vs ROCK ：LOSE
PAPER vs SCISSORS ：LOSE
PAPER vs PAPER ：DRAW
*/
